home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / pibt40s5.arc / RECEIVK2.MOD next >
Text File  |  1987-09-16  |  54KB  |  1,510 lines

  1. (*----------------------------------------------------------------------*)
  2. (*     Kermit_Receive_File --- get file data from remote Kermit         *)
  3. (*----------------------------------------------------------------------*)
  4.  
  5. PROCEDURE Kermit_Receive_File;
  6.  
  7. (*----------------------------------------------------------------------*)
  8. (*                                                                      *)
  9. (*     Procedure:  Kermit_Receive_File                                  *)
  10. (*                                                                      *)
  11. (*     Purpose:    Gets file data from remote Kermit                    *)
  12. (*                                                                      *)
  13. (*     Calling Sequence:                                                *)
  14. (*                                                                      *)
  15. (*        Kermit_Receive_File;                                          *)
  16. (*                                                                      *)
  17. (*     Remarks:                                                         *)
  18. (*                                                                      *)
  19. (*        This procedure receives file data from the remote Kermit      *)
  20. (*        until a Break packet, and End packet, or an Unknown packet    *)
  21. (*        is received.  It will also abort if there are too many        *)
  22. (*        retries.                                                      *)
  23. (*                                                                      *)
  24. (*----------------------------------------------------------------------*)
  25.  
  26. VAR
  27.    Try               : INTEGER;
  28.    Save_Retry        : INTEGER;
  29.    Data_Place        : INTEGER;
  30.    Windowing_Started : BOOLEAN;
  31.  
  32. (*----------------------------------------------------------------------*)
  33. (*             Send_Abort_Packet --- Send abort transfer request        *)
  34. (*----------------------------------------------------------------------*)
  35.  
  36. PROCEDURE Send_Abort_Packet;
  37.  
  38. BEGIN (* Send_Abort_Packet *)
  39.                                    (* Send appropriate abort packet *)
  40.    CASE Kermit_Abort_Level OF
  41.  
  42.       One_File:         BEGIN
  43.                            Send_Packet_Ptr^[4] := 'Y';
  44.                            Send_Packet_Ptr^[5] := 'X';
  45.                            Send_Packet_Length  := 5;
  46.                            Display_Kermit_Message_2('Cancelling transfer of current file.');
  47.                         END;
  48.  
  49.       Entire_Protocol:  BEGIN
  50.                            Receive_Done       := TRUE;
  51.                            Abort_Done         := TRUE;
  52.                            Display_Kermit_Message_2('Cancelling entire protocol.');
  53.                         END;
  54.  
  55.       All_Files:        BEGIN
  56.                            Send_Packet_Ptr^[4] := 'Y';
  57.                            Send_Packet_Ptr^[5] := 'Z';
  58.                            Send_Packet_Length  := 5;
  59.                            Display_Kermit_Message_2('Cancelling transfer of all files.');
  60.                         END;
  61.       ELSE
  62.                         BEGIN
  63.                            Send_Packet_Ptr^[4] := 'N';
  64.                            Send_Packet_Length  := 4;
  65.                         END;
  66.    END (* CASE *);
  67.                                    (* Construct and send abort packet *)
  68.  
  69.    IF ( Kermit_Abort_Level <> Entire_Protocol ) THEN
  70.       BEGIN
  71.          Build_Packet;
  72.          Send_Packet;
  73.       END;
  74.                                    (* Ensure file tossed out *)
  75.    Toss_File := TRUE;
  76.  
  77. END   (* Send_Abort_Packet *);
  78.  
  79. (*----------------------------------------------------------------------*)
  80. (*           Handle_Attrib_Pack --- handle one attribute packet         *)
  81. (*----------------------------------------------------------------------*)
  82.  
  83. PROCEDURE Handle_Attrib_Pack;
  84.  
  85. VAR
  86.    InPos            : INTEGER;
  87.    I                : INTEGER;
  88.    J                : INTEGER;
  89.    Len_Packet       : INTEGER;
  90.    Rejected_Attribs : FileStr;
  91.    L_Attrib         : INTEGER;
  92.    L_Attrib_Last    : INTEGER;
  93.    Attrib           : CHAR;
  94.    Date_String      : STRING[10];
  95.    Time_String      : STRING[10];
  96.    Year             : INTEGER;
  97.    Month            : INTEGER;
  98.    Day              : INTEGER;
  99.    Hour             : INTEGER;
  100.    Mins             : INTEGER;
  101.    Secs             : INTEGER;
  102.    Size_String      : STRING[10];
  103.  
  104. (*----------------------------------------------------------------------*)
  105.  
  106. FUNCTION Get_Number( S: AnyStr ) : INTEGER;
  107.  
  108. VAR
  109.    J   : INTEGER;
  110.    Sum : INTEGER;
  111.  
  112. BEGIN (* Get_Number *)
  113.  
  114.    Sum := 0;
  115.  
  116.    FOR J := 1 TO LENGTH( S ) DO
  117.       Sum := Sum * 10 + ORD( S[J] ) - ORD('0');
  118.  
  119.    Get_Number := Sum;
  120.  
  121. END   (* Get_Number *);
  122.  
  123. (*----------------------------------------------------------------------*)
  124.  
  125. PROCEDURE Extract_File_Date;
  126.  
  127. BEGIN (* Extract_File_Date *)
  128.  
  129.    Date_String      := '';
  130.    Kermit_File_Date := 0;
  131.                                    (* Extract date string *)
  132.  
  133.    WHILE ( ( I <= L_Attrib_Last ) AND ( Rec_Packet_Ptr^[I] <> ' ' ) ) DO
  134.       BEGIN
  135.          Date_String := Date_String + Rec_Packet_Ptr^[I];
  136.          I           := SUCC( I );
  137.       END;
  138.                                    (* Pull apart date string.          *)
  139.                                    (* Note:  year may be 2 or 4 digits *)
  140.  
  141.    IF ( LENGTH( Date_String ) = 6 ) THEN
  142.       BEGIN
  143.          Year  := Get_Number( Date_String[1] + Date_String[2] ) + 1900;
  144.          Month := Get_Number( Date_String[3] + Date_String[4] );
  145.          Day   := Get_Number( Date_String[5] + Date_String[6] );
  146.       END
  147.    ELSE IF ( LENGTH( Date_String ) = 8 ) THEN
  148.       BEGIN
  149.          Year  := Get_Number( COPY( Date_String, 1, 4 ) );
  150.          Month := Get_Number( Date_String[5] + Date_String[6] );
  151.          Day   := Get_Number( Date_String[7] + Date_String[8] );
  152.       END
  153.    ELSE
  154.       BEGIN
  155.          Year  := 0;
  156.          Month := 0;
  157.          Day   := 0;
  158.       END;
  159.                                    (* Convert date to DOS form *)
  160.  
  161.    Kermit_File_Date := MAX( Year - 1980 , 0 ) SHL 9 + Month SHL 5 + Day;
  162.  
  163.    Kermit_Do_File_Date := ( Kermit_File_Date <> 0 );
  164. {
  165.    IF Kermit_Debug THEN
  166.       BEGIN
  167.          Write_Log('Date_String = <' + Date_String + '>', FALSE, FALSE );
  168.          IF Kermit_Do_File_Date THEN
  169.             Write_Log( 'Do_Date = YES', FALSE, FALSE )
  170.          ELSE
  171.             Write_Log( 'Do_Date = NO', FALSE, FALSE );
  172.          Write_Log('   I        = ' + IToS( I ), FALSE, FALSE );
  173.          Write_Log('   L_Attrib_Last = ' + IToS( L_Attrib_Last ), FALSE, FALSE );
  174.       END;
  175. }
  176. END   (* Extract_File_Date *);
  177.  
  178. (*----------------------------------------------------------------------*)
  179.  
  180. PROCEDURE Extract_File_Time;
  181.  
  182. BEGIN (* Extract_File_Time *)
  183.  
  184.    Time_String      := '';
  185.    Kermit_File_Time := 0;
  186. {
  187.    IF Kermit_Debug THEN
  188.       BEGIN
  189.          Write_Log('Extract_File_Time', FALSE, FALSE );
  190.          Write_Log('   I        = ' + IToS( I ), FALSE, FALSE );
  191.          Write_Log('   L_Attrib_Last = ' + IToS( L_Attrib_Last ), FALSE, FALSE );
  192.       END;
  193. }
  194.    IF ( I < L_Attrib_Last ) THEN
  195.       BEGIN
  196.          IF ( Rec_Packet_Ptr^[I] = ' ' ) THEN
  197.             I := SUCC( I );
  198.          WHILE ( I <= L_Attrib_Last ) DO
  199.             BEGIN
  200.                Time_String := Time_String + Rec_Packet_Ptr^[I];
  201.                I           := SUCC( I );
  202.             END;
  203.       END;
  204.                                    (* Pull apart time string.  *)
  205.    IF ( Time_String <> '' ) THEN
  206.       BEGIN
  207.  
  208.          Hour  := Get_Number( Time_String[1] + Time_String[2] );
  209.          Mins  := Get_Number( Time_String[4] + Time_String[5] );
  210.  
  211.          IF ( LENGTH( Time_String ) > 5 ) THEN
  212.             Secs  := Get_Number( Time_String[7] + Time_String[8] )
  213.          ELSE
  214.             Secs  := 0;
  215.                                    (* Convert time to DOS form *)
  216.  
  217.          Kermit_File_Time := Hour SHL 11 OR Mins SHL 5 OR ( Secs DIV 2 );
  218.  
  219.          Kermit_Do_File_Time := TRUE;
  220.  
  221.       END;
  222. {
  223.    IF Kermit_Debug THEN
  224.       BEGIN
  225.          Write_Log('Time_String = <' + Time_String + '>', FALSE, FALSE );
  226.          IF Kermit_Do_File_Time THEN
  227.             Write_Log( 'Do_Time = YES', FALSE, FALSE )
  228.          ELSE
  229.             Write_Log( 'Do_Time = NO', FALSE, FALSE );
  230.       END;
  231. }
  232. END   (* Extract_File_Time *);
  233.  
  234. (*----------------------------------------------------------------------*)
  235.  
  236. BEGIN (* Handle_Attrib_Pack *)
  237.                                    (* Start of received packet     *)
  238.    InPos            := 1;
  239.    Len_Packet       := Rec_Packet_Length;
  240.    Rejected_Attribs := '';
  241. {
  242.    IF Kermit_Debug THEN
  243.       Write_Log('Attribute packet = <' +
  244.                 COPY( Rec_Packet_Ptr^, 1, Rec_Packet_Length ) +
  245.                 '>', FALSE, FALSE );
  246. }
  247.                                    (* Pick up attributes           *)
  248.    WHILE ( InPos < Len_Packet ) DO
  249.       BEGIN
  250.  
  251.          Attrib        := Rec_Packet_Ptr^[InPos];
  252.          L_Attrib      := ORD( Rec_Packet_Ptr^[InPos+1] ) - 32;
  253.          I             := InPos + 2;
  254.          L_Attrib_Last := L_Attrib + PRED( I );
  255. {
  256.          IF Kermit_Debug THEN
  257.             BEGIN
  258.                Write_Log('   Attribute = <' + Attrib + '>', FALSE, FALSE );
  259.             END;
  260. }
  261.          IF Kermit_Attributes THEN
  262.  
  263.             CASE Attrib OF
  264.  
  265.                '!': BEGIN (* Get approximate file size *)
  266.  
  267.                        Kermit_File_Size := Get_Number( COPY( Rec_Packet_Ptr^, I, L_Attrib ) );
  268.  
  269.                        IF Display_Status THEN
  270.                           BEGIN
  271.                              GoToXY( 25 , 4 );
  272.                              STR( Kermit_File_Size : 10 : 0 , Size_String );
  273.                              WHILE ( POS( ' ' , Size_String ) > 0 ) DO
  274.                                 DELETE( Size_String, POS( ' ' , Size_String ), 1 );
  275.                              WRITE( Size_String , 'K' );
  276.                              ClrEol;
  277.                           END;
  278.  
  279.                     END   (* Get approximate file size *);
  280.  
  281.                '#': BEGIN (* Get date/time of file creation *)
  282.                        Extract_File_Date;
  283.                        Extract_File_Time;
  284.                     END;
  285.  
  286.                '1': BEGIN (* Get exact file size *)
  287.  
  288.                        Kermit_File_Size := 0.0;
  289.  
  290.                        FOR J := I TO ( I + L_Attrib - 1 ) DO
  291.                           IF Rec_Packet_Ptr^[J] IN ['0'..'9'] THEN
  292.                              Kermit_File_Size := Kermit_File_Size * 10.0 +
  293.                                                  ( ORD( Rec_Packet_Ptr^[J] ) - ORD('0') );
  294.  
  295.                        IF Display_Status THEN
  296.                           BEGIN
  297.                              GoToXY( 25 , 4 );
  298.                              STR( Kermit_File_Size : 10 : 0 , Size_String );
  299.                              WHILE ( POS( ' ' , Size_String ) > 0 ) DO
  300.                                 DELETE( Size_String, POS( ' ' , Size_String ), 1 );
  301.                              WRITE( Size_String );
  302.                              ClrEol;
  303.                           END;
  304.  
  305.                     END   (* Get exact file size *);
  306.  
  307.                ELSE
  308.                   Rejected_Attribs := Rejected_Attribs + Attrib;
  309.  
  310.             END (* CASE *)
  311.  
  312.          ELSE
  313.             Rejected_Attribs := Rejected_Attribs + Attrib;
  314.  
  315.          InPos := InPos + L_Attrib + 2;
  316.  
  317.       END;
  318.                                    (* Acknowledge this packet *)
  319.    IF Kermit_Abort THEN
  320.       Send_Abort_Packet
  321.    ELSE
  322.       Send_ACK;
  323.  
  324. END   (* Handle_Attrib_Pack *);
  325.  
  326. (*----------------------------------------------------------------------*)
  327. (*             Handle_Data_Pack --- handle one data packet              *)
  328. (*----------------------------------------------------------------------*)
  329.  
  330. PROCEDURE Handle_Data_Pack;
  331.  
  332. BEGIN (* Handle_Data_Pack *)
  333.                                    (* If abort pending, send abort  *)
  334.                                    (* packet and don't expand data. *)
  335.    IF Kermit_Abort THEN
  336.       Send_Abort_Packet
  337.    ELSE
  338.       BEGIN
  339.                                    (* Else, send ACK for the data *)
  340.                                    (* packet ... *)
  341.          Send_ACK;
  342.                                    (* ... and expand data packet. *)
  343.  
  344.          IF ( NOT Expand_Packet( Rec_Packet_Ptr , Rec_Packet_Length ) ) THEN
  345.             BEGIN
  346.                Kermit_Abort       := TRUE;
  347.                Kermit_Abort_Level := One_File;
  348.             END;
  349.  
  350.       END;
  351.  
  352. END   (* Handle_Data_Pack *);
  353.  
  354. (*----------------------------------------------------------------------*)
  355. (*             Handle_End_Pack --- handle end of file packet            *)
  356. (*----------------------------------------------------------------------*)
  357.  
  358. PROCEDURE Handle_End_Pack;
  359.  
  360. VAR
  361.    Write_Count   : INTEGER;
  362.    Err           : INTEGER;
  363.    Ctrl_Z_Written: BOOLEAN;
  364.  
  365. BEGIN (* Handle_End_Pack *)
  366.                                    (* Write any remaining characters *)
  367.                                    (* in file buffer to file and     *)
  368.                                    (* close it.                      *)
  369.    Err := 0;
  370.  
  371.    IF File_Open THEN
  372.       BEGIN
  373.                                    (* Add a Ctrl-Z to file if in     *)
  374.                                    (* text mode to mark end of file. *)
  375.  
  376.          Ctrl_Z_Written := FALSE;
  377.  
  378.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  379.             IF ( Write_Buffer^[Buffer_Pos] <> ORD( ^Z ) ) THEN
  380.                IF ( Buffer_Pos < Buffer_Size ) THEN
  381.                   BEGIN
  382.                      Buffer_Pos                := SUCC( Buffer_Pos );
  383.                      Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  384.                      Ctrl_Z_Written            := TRUE;
  385.                      Buffer_Num                := Buffer_Num + 1;
  386.                   END;
  387.                                    (* Write any remaining characters in *)
  388.                                    (* buffer.                           *)
  389.  
  390.          Write_Count := Buffer_Pos;
  391.  
  392.          Err         := Write_File_Handle( XFile_Handle, Write_Buffer^,
  393.                                            Write_Count );
  394.  
  395.          IF ( Write_Count <> Buffer_Pos ) THEN
  396.             Err := 1;
  397.                                    (* Write a Ctrl-Z to file if in     *)
  398.                                    (* text mode and no room in buffer. *)
  399.  
  400.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  401.             ( NOT Ctrl_Z_Written ) THEN
  402.             BEGIN
  403.                Write_Buffer^[1] := ORD( ^Z );
  404.                Write_Count      := 1;
  405.                Err              := Err + Write_File_Handle( XFile_Handle,
  406.                                                             Write_Buffer^,
  407.                                                             Write_Count );
  408.                IF ( Write_Count <> 1 ) THEN
  409.                   Err := 1;
  410.                Buffer_Num       := Buffer_Num + 1;
  411.             END;
  412.                                    (* Set file date and time *)
  413.  
  414.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  415.             Use_Time_Sent THEN
  416.                Err  := Dir_Set_File_Date_And_Time( XFile_Handle,
  417.                                                    Kermit_File_Date,
  418.                                                    Kermit_File_Time );
  419.  
  420.                                    (* Close the file *)
  421.  
  422.          IF ( Close_File_Handle( XFile_Handle ) <> 0 ) THEN
  423.             Err := 1;
  424.                                    (* Mark file as closed. *)
  425.          File_Open   := FALSE;
  426.                                    (* Add char count this file *)
  427.                                    (* to running total         *)
  428.  
  429.          Buffer_Total := Buffer_Total + Buffer_Num;
  430.  
  431.       END;
  432.  
  433.                                    (* Acknowledge last record  *)
  434.    IF ( Err = 0 ) THEN
  435.       Send_ACK
  436.    ELSE
  437.       BEGIN
  438.          Kermit_Abort       := TRUE;
  439.          Kermit_Abort_Level := One_File;
  440.          Send_Abort_Packet;
  441.                                    (* Allow reception of further packets *)
  442.  
  443.          Kermit_Abort       := FALSE;
  444.          Kermit_Abort_Level := No_Abort;
  445.       END;
  446.                                    (* And go back to waiting for *)
  447.                                    (* start of next file.        *)
  448.    Kermit_State := Receive_Header;
  449.  
  450.                                    (* Toss this file if necessary *)
  451.  
  452.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  453.       BEGIN
  454.          Err := Dir_Delete_File( Full_Name );
  455.          Err := INT24Result;
  456.       END;
  457.  
  458. END   (* Handle_End_Pack *);
  459.  
  460. (*----------------------------------------------------------------------*)
  461. (*             Handle_Break_Packet --- Handle break packet              *)
  462. (*----------------------------------------------------------------------*)
  463.  
  464. PROCEDURE Handle_Break_Pack;
  465.  
  466. VAR
  467.    Write_Count   : INTEGER;
  468.    Err           : INTEGER;
  469.    Ctrl_Z_Written: BOOLEAN;
  470.  
  471. BEGIN (* Handle_Break_Pack *)
  472.                                    (* Write any remaining characters *)
  473.                                    (* in file buffer to file and     *)
  474.                                    (* close it.                      *)
  475.    Err := 0;
  476.  
  477.    IF File_Open THEN
  478.       BEGIN
  479.                                    (* Add a Ctrl-Z to file if in     *)
  480.                                    (* text mode to mark end of file. *)
  481.  
  482.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) THEN
  483.             IF ( Buffer_Pos < Buffer_Size ) THEN
  484.                BEGIN
  485.                   Buffer_Num                := Buffer_Num + 1;
  486.                   Buffer_Pos                := SUCC( Buffer_Pos );
  487.                   Write_Buffer^[Buffer_Pos] := ORD( ^Z );
  488.                   Ctrl_Z_Written            := TRUE;
  489.                END
  490.             ELSE
  491.                Ctrl_Z_Written := FALSE;
  492.  
  493.                                    (* Write any remaining characters in *)
  494.                                    (* buffer.                           *)
  495.  
  496.          Write_Count := Buffer_Pos;
  497.  
  498.          Err         := Write_File_Handle( XFile_Handle, Write_Buffer^,
  499.                                            Write_Count );
  500.  
  501.          IF ( Write_Count <> Buffer_Pos ) THEN
  502.             Err := 1;
  503.                                    (* Write a Ctrl-Z to file if in     *)
  504.                                    (* text mode and no room in buffer. *)
  505.  
  506.          IF ( Kermit_File_Type_Var = Kermit_Ascii ) AND
  507.             ( NOT Ctrl_Z_Written ) THEN
  508.             BEGIN
  509.                Buffer_Num       := Buffer_Num + 1;
  510.                Write_Buffer^[1] := ORD( ^Z );
  511.                Write_Count      := 1;
  512.                IF ( Write_File_Handle( XFile_Handle, Write_Buffer^, Write_Count ) <> 0 ) THEN
  513.                   Err := 1;
  514.                IF ( Write_Count <> 1 ) THEN
  515.                   Err := 1;
  516.             END;
  517.                                    (* Set file date and time *)
  518.  
  519.          IF ( Kermit_Do_File_Date OR Kermit_Do_File_Time ) AND
  520.             Use_Time_Sent THEN
  521.                Err  := Dir_Set_File_Date_And_Time( XFile_Handle,
  522.                                                    Kermit_File_Date,
  523.                                                    Kermit_File_Time );
  524.  
  525.                                    (* Close the file *)
  526.  
  527.          IF ( Close_File_Handle( XFile_Handle ) <> 0 ) THEN
  528.             Err := 1;
  529.                                    (* Mark file as closed. *)
  530.          File_Open   := FALSE;
  531.                                    (* Add char count this file *)
  532.                                    (* to running total         *)
  533.  
  534.          Buffer_Total := Buffer_Total + Buffer_Num;
  535.  
  536.       END;
  537.                                    (* Acknowledge this packet *)
  538.    IF ( Err = 0 ) THEN
  539.       Send_ACK
  540.    ELSE
  541.       BEGIN
  542.          Kermit_Abort       := TRUE;
  543.          Kermit_Abort_Level := One_File;
  544.          Send_Abort_Packet;
  545.                                    (* Allow reception of further packets *)
  546.          Kermit_Abort       := FALSE;
  547.          Kermit_Abort_Level := No_Abort;
  548.       END;
  549.                                    (* We're done with this batch of files. *)
  550.    Receive_Done := TRUE;
  551.                                    (* Toss this file if necessary *)
  552.  
  553.    IF ( Toss_File AND Evict_Partial_Trans ) THEN
  554.       BEGIN
  555.          Err := Dir_Delete_File( Full_Name );
  556.          Err := INT24Result;
  557.       END;
  558.  
  559. END   (* Handle_Break_Pack *);
  560.  
  561. (*----------------------------------------------------------------------*)
  562. (*           Expand_Bottom_Packet --- Expand bottom packet in table     *)
  563. (*----------------------------------------------------------------------*)
  564.  
  565. PROCEDURE Expand_Bottom_Packet;
  566.  
  567. VAR
  568.    Data_Ptr : Kermit_Packet_Ptr;
  569.    Data_Len : INTEGER;
  570.  
  571. BEGIN (* Expand_Bottom_Packet *)
  572.  
  573.    IF Kermit_Queue[Kermit_Window_Bottom].ACK_Flag THEN
  574.       BEGIN
  575.                                    (* Expand the bottom packet in the *)
  576.                                    (* window and write it to disk.    *)
  577.  
  578.          WITH Kermit_Queue[Kermit_Window_Bottom] DO
  579.             BEGIN
  580.                Data_Ptr := ADDR( Sector_Data[ Data_Slot ] );
  581.                Data_Len := Data_Length;
  582. {
  583.                IF Kermit_Debug THEN
  584.                   BEGIN
  585.                      Write_Log( 'Expand packet = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  586.                      Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , FALSE, FALSE );
  587.                      Write_Log( 'Data_Len  = ' + IToS( Data_Len           ) , FALSE, FALSE );
  588.                   END;
  589. }
  590.             END;
  591.  
  592.  
  593.          IF ( NOT Expand_Packet( Data_Ptr , Data_Len ) ) THEN
  594.             BEGIN
  595.                Kermit_Abort       := TRUE;
  596.                Kermit_Abort_Level := One_File;
  597.             END;
  598.                                    (* Move up bottom of the table. *)
  599.  
  600.          Kermit_Window_Bottom := SUCC( Kermit_Window_Bottom ) MOD 64;
  601.          Kermit_Window_Used   := PRED( Kermit_Window_Used   );
  602.  
  603.       END
  604.    ELSE
  605.       BEGIN
  606.                                    (* If there's no room in the table for *)
  607.                                    (* the new packet, abort the transfer. *)
  608.  
  609.          Kermit_Abort       := TRUE;
  610.          Kermit_Abort_Level := One_File;
  611.  
  612.          Display_Kermit_Message_2('Apparent deadlock, transfer cancelled.');
  613.  
  614.       END;
  615.  
  616. END   (* Expand_Bottom_Packet *);
  617.  
  618. (*----------------------------------------------------------------------*)
  619. (* Handle_Windowed_Data_Pack --- Handle data packet in windowed transfer*)
  620. (*----------------------------------------------------------------------*)
  621.  
  622. PROCEDURE Handle_Windowed_Data_Pack;
  623.  
  624. VAR
  625.    Data_Ptr : Kermit_Packet_Ptr;
  626.    Data_Len : INTEGER;
  627.    Pack_Num : INTEGER;
  628.    Last_Num : INTEGER;
  629.    Do_Insert: BOOLEAN;
  630.  
  631. (*----------------------------------------------------------------------*)
  632. (*     Insert_Packet_In_Table --- Insert received packet into table     *)
  633. (*----------------------------------------------------------------------*)
  634.  
  635. PROCEDURE Insert_Packet_In_Table;
  636.  
  637. BEGIN (* Insert_Packet_In_Table *)
  638.  
  639.                                    (* Get offset to store data. *)
  640.  
  641.    Data_Place           := Data_Place + 96;
  642.  
  643.    IF ( ( Data_Place + 96 ) > MaxSectorLength ) THEN
  644.       Data_Place := Receive_Offset;
  645.  
  646.                                    (* Insert received packet data into table. *)
  647.  
  648.    WITH Kermit_Queue[Rec_Packet_Num] DO
  649.       BEGIN
  650.          Data_Slot       := Data_Place;
  651. {
  652.          IF Kermit_Debug THEN
  653.             BEGIN
  654.                Write_Log( '---Insert packet --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  655.                Write_Log( 'Data_Slot = ' + IToS( Data_Slot          ) , TRUE, FALSE );
  656.                Write_Log( 'Length    = ' + IToS( Rec_Packet_Length  ) , TRUE, FALSE );
  657.                Write_Log( '---End Insert    --- ' , TRUE, FALSE );
  658.             END;
  659. }
  660.          ACK_Flag        := TRUE;
  661.          Retry_Count     := 0;
  662.          Data_Length     := Rec_Packet_Length;
  663.          MOVE( Rec_Packet_Ptr^[1], Sector_Data[Data_Slot],
  664.                Rec_Packet_Length );
  665.       END;
  666.  
  667. END   (* Insert_Packet_In_Table *);
  668.  
  669. (*----------------------------------------------------------------------*)
  670. (*     PacketBeyondWindow  --- Test if packet beyond current window     *)
  671. (*----------------------------------------------------------------------*)
  672.  
  673. FUNCTION PacketBeyondWindow : BOOLEAN;
  674.  
  675. VAR
  676.    Low : INTEGER;
  677.    High: INTEGER;
  678.  
  679. BEGIN (* PacketBeyondWindow *)
  680.  
  681.    Low  := ( Kermit_Window_Top + 2           ) MOD 64;
  682.    High := ( Kermit_Window_Top + Window_Size_Used ) MOD 64;
  683.  
  684.    WHILE ( Low <> High ) AND ( Rec_Packet_Num <> Low ) DO
  685.       Low := SUCC( Low ) MOD 64;
  686.  
  687.    PacketBeyondWindow := ( Low = Rec_Packet_Num );
  688.  
  689. END   (* PacketBeyondWindow *);
  690.  
  691. (*----------------------------------------------------------------------*)
  692.  
  693. BEGIN (* Handle_Windowed_Data_Pack *)
  694.  
  695.                                    (* Indicate windowing has started   *)
  696.  
  697.    IF ( NOT Windowing_Started ) THEN
  698.       BEGIN
  699.          Windowing_Started     := TRUE;
  700.          Kermit_Window_Top     := PRED( Packet_Num ) MOD 64;
  701.          Kermit_Window_Bottom  := Packet_Num;
  702.          Kermit_Doing_Transfer := TRUE;
  703.       END;
  704.                                    (* ACKnowledge the received packet. *)
  705.    Send_ACK;
  706.                                    (* Assume we'll be inserting packet *)
  707.                                    (* into table.                      *)
  708.    Do_Insert := TRUE;
  709.                                    (* Check the sequence number of the *)
  710.                                    (* received data packet against the *)
  711.                                    (* current table bounds.            *)
  712.  
  713.    IF ( Rec_Packet_Num = ( SUCC( Kermit_Window_Top ) MOD 64 ) ) THEN
  714.       BEGIN (* Next packet in sequence *)
  715. {
  716.          IF Kermit_Debug THEN
  717.             Write_Log( '--- Next packet in sequence --- = ' + IToS( Rec_Packet_Num ) , FALSE, FALSE );
  718. }
  719.                                    (* We got the next packet in sequence. *)
  720.                                    (* See if we have to rotate the table  *)
  721.                                    (* to insert this entry.               *)
  722.  
  723.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  724.             Expand_Bottom_Packet;
  725.  
  726.                                    (* If we didn't abort, put the new packet *)
  727.                                    (* in the top window slot.                *)
  728.  
  729.          Kermit_Window_Top    := SUCC( Kermit_Window_Top  ) MOD 64;
  730.          Kermit_Window_Used   := SUCC( Kermit_Window_Used );
  731.  
  732.       END (* Next packet in sequence *)
  733.  
  734.                                    (* Handle packet which fits into body of *)
  735.                                    (* table as simple insert.               *)
  736.    ELSE IF PacketInWindow THEN
  737.       (* Nothing to do here *)
  738. {
  739.       BEGIN
  740.          IF Kermit_Debug THEN
  741.             Write_Log('--- Packet was in window --- ', FALSE, FALSE);
  742.       END
  743. }
  744.                                    (* Packet is beyond current window. *)
  745.                                    (* Some packets were lost.          *)
  746.    ELSE IF PacketBeyondWindow THEN
  747.  
  748.                                    (* Packet is beyond current window. *)
  749.                                    (* Some packets were lost.          *)
  750.       BEGIN
  751.                                    (* NAK the missing packets.  Also,  *)
  752.                                    (* rotate the table up to fit in    *)
  753.                                    (* this new packet.  If we can't,   *)
  754.                                    (* abort the transfer.              *)
  755. {
  756.          IF Kermit_Debug THEN
  757.             Write_Log('--- Packet beyond window --- ', FALSE, FALSE);
  758. }
  759.          Pack_Num := SUCC( Kermit_Window_Top ) MOD 64;
  760.  
  761.          REPEAT
  762. {
  763.             IF Kermit_Debug THEN
  764.                Write_Log('---    Pack_Num = ' + IToS( Pack_Num ), FALSE, FALSE);
  765. }
  766.             Packet_Num := Pack_Num;
  767.             Send_NAK;
  768.  
  769.             IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  770.                Expand_Bottom_Packet;
  771.  
  772.             Kermit_Queue[Pack_Num].ACK_Flag := FALSE;
  773.  
  774.                                    (* Set up to insert the packet at the *)
  775.                                    (* new top of the rotated table.      *)
  776.  
  777.             Pack_Num             := SUCC( Pack_Num ) MOD 64;
  778.             Kermit_Window_Top    := SUCC( Kermit_Window_Top  ) MOD 64;
  779.             Kermit_Window_Used   := SUCC( Kermit_Window_Used );
  780.  
  781.          UNTIL ( ( Pack_Num = Rec_Packet_Num ) OR Kermit_Abort );
  782.  
  783.                                    (* We may still need one more rotation *)
  784.  
  785.          IF ( Kermit_Window_Used = Window_Size_Used ) THEN
  786.             Expand_Bottom_Packet;
  787.  
  788.                                    (* If we didn't abort, put the new packet *)
  789.                                    (* in the top window slot.                *)
  790.  
  791.          Kermit_Window_Top    := SUCC( Kermit_Window_Top  ) MOD 64;
  792.          Kermit_Window_Used   := SUCC( Kermit_Window_Used );
  793. {
  794.          IF Kermit_Debug THEN
  795.             BEGIN
  796.                Write_Log('      New Window_Top    = ' + IToS( Kermit_Window_Top ),
  797.                          FALSE, FALSE );
  798.                Write_Log('      New Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  799.                          FALSE, FALSE );
  800.             END;
  801. }
  802.       END
  803.                                    (* Packet is completely bogus -- ignore it. *)
  804.    ELSE
  805.       Do_Insert := FALSE;
  806.  
  807.                                    (* Insert packet into table.       *)
  808.    IF ( NOT Kermit_Abort ) THEN
  809.       BEGIN
  810.          IF Do_Insert THEN
  811.             Insert_Packet_In_Table;
  812.       END
  813.    ELSE                            (* Send abort packet if necessary. *)
  814.       Send_Abort_Packet;
  815.  
  816. END   (* Handle_Windowed_Data_Pack *);
  817.  
  818. (*----------------------------------------------------------------------*)
  819. (*              Receive_Normal --- Receive file without windowing       *)
  820. (*----------------------------------------------------------------------*)
  821.  
  822. PROCEDURE Receive_Normal;
  823.  
  824. BEGIN (* Receive_Normal *)
  825.                                    (* Indicate transfer has started.  *)
  826.    Kermit_Doing_Transfer := TRUE;
  827.  
  828.                                    (* Loop over packets in file being *)
  829.                                    (* received.                       *)
  830.    REPEAT
  831.                                    (* Number of tries for a good packet *)
  832.       Try := 0;
  833.  
  834.       REPEAT
  835.                                    (* Get next packet *)
  836.          Receive_Packet;
  837.  
  838.          CASE Packet_OK OF
  839.                                    (* If packet bad *)
  840.  
  841.             FALSE : IF ( NOT Kermit_Abort ) THEN
  842.                        BEGIN
  843.                           Try := SUCC( Try );
  844.                           IF ( Try = Kermit_MaxTry ) THEN
  845.                              BEGIN
  846.                                 Kermit_Abort       := TRUE;
  847.                                 Kermit_Abort_Level := One_File;
  848.                                 Kermit_Construct_Message( 'EToo many retries.' );
  849.                              END
  850.                           ELSE
  851.                              Send_NAK;
  852.                        END
  853.                     ELSE
  854.                        BEGIN
  855.                           Packet_Num           := SUCC( Packet_Num ) MOD 64;
  856.                           Kermit_Window_Top    := Rec_Packet_Num;
  857.                           Kermit_Window_Bottom := Rec_Packet_Num;
  858.                           Send_Abort_Packet;
  859.                        END;
  860.  
  861.                                    (* If packet OK *)
  862.              TRUE : BEGIN
  863.                                    (* Duplicate packet -- just ACK and *)
  864.                                    (* continue.                        *)
  865.  
  866.                        IF ( Packet_Num = Rec_Packet_Num ) THEN
  867.                           Send_ACK
  868.                        ELSE
  869.                           BEGIN
  870.  
  871.                              Packet_Num           := Rec_Packet_Num;
  872.                              Kermit_Window_Top    := Rec_Packet_Num;
  873.                              Kermit_Window_Bottom := Rec_Packet_Num;
  874.  
  875.                              CASE Kermit_Packet_Type OF
  876.                                 Data_Pack  : Handle_Data_Pack;
  877.                                 End_Pack   : Handle_End_Pack;
  878.                                 Break_Pack : Handle_Break_Pack;
  879.                                 Attrib_Pack: Handle_Attrib_Pack;
  880.                                 Header_Pack: ;
  881.                                 ELSE         Send_NAK;
  882.                              END  (* CASE *);
  883.  
  884.                           END;
  885.                     END;
  886.  
  887.          END (* CASE *);
  888.  
  889.       UNTIL ( Packet_OK OR Kermit_Abort );
  890.  
  891.    UNTIL ( Receive_Done OR Kermit_Abort OR
  892.            ( Kermit_Packet_Type = Header_Pack ) );
  893.  
  894. END (* Receive_Normal *);
  895.  
  896. (*----------------------------------------------------------------------*)
  897. (*              Receive_Windowing --- Receive file with windowing       *)
  898. (*----------------------------------------------------------------------*)
  899.  
  900. PROCEDURE Receive_Windowing;
  901.  
  902. (*----------------------------------------------------------------------*)
  903. (*   Send_NAK_For_Most_Desired --- Send NAK for most desired packet     *)
  904. (*----------------------------------------------------------------------*)
  905.  
  906. PROCEDURE Send_NAK_For_Most_Desired;
  907.  
  908. VAR
  909.    L: INTEGER;
  910.  
  911. BEGIN (* Send_NAK_For_Most_Desired *)
  912.  
  913.                                    (* If windowing started -- i.e.,  *)
  914.                                    (* a data packet has appeared --  *)
  915.                                    (* then send NAK for most desired *)
  916.                                    (* packet.  Else, send ordinary   *)
  917.                                    (* NAK.                           *)
  918.    IF Windowing_Started THEN
  919.       BEGIN
  920.                                    (* Send NAK for most wanted packet. *)
  921.                                    (* This is the first unACKd packet  *)
  922.                                    (* in the table, or, if all are     *)
  923.                                    (* ACKd, the first packet beyond    *)
  924.                                    (* the table.                       *)
  925.  
  926.          IF ( Kermit_Window_Used > 0 ) THEN
  927.             BEGIN
  928.                Packet_Num := Kermit_Window_Bottom;
  929.                WHILE ( ( Packet_Num <> Kermit_Window_Top   ) AND
  930.                        ( Kermit_Queue[Packet_Num].ACK_Flag ) ) DO
  931.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  932.                IF Kermit_Queue[Packet_Num].ACK_Flag THEN
  933.                   Packet_Num := SUCC( Packet_Num ) MOD 64;
  934.             END
  935.          ELSE
  936.             Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  937.  
  938.                                    (* Clear possible bogus XOFF received *)
  939.                                    (* by remote system.                  *)
  940.  
  941.          IF Async_Do_XonXoff THEN
  942.             IF ( NOT Async_XOFF_Sent ) THEN
  943.                Async_Send( CHR( XON ) );
  944.  
  945.                                    (* If we timed out, send NAK, else    *)
  946.                                    (* ignore the bad packet.             *)
  947.  
  948.          IF Kermit_Retry THEN
  949.             Send_NAK;
  950.  
  951.       END
  952.    ELSE                            (* Send ordinary NAK if no windowing yet *)
  953.       BEGIN
  954.          Send_NAK;
  955.       END;
  956. {
  957.    IF Kermit_Debug THEN
  958.       BEGIN
  959.          Write_Log( 'Send_NAK_For_Most_Desired = ' + IToS( Packet_Num ), FALSE,
  960.                     FALSE );
  961.          Write_Log('   Window_Top    = ' + IToS( Kermit_Window_Top ),
  962.                    FALSE, FALSE );
  963.          Write_Log('   Window_Bottom = ' + IToS( Kermit_Window_Bottom ),
  964.                    FALSE, FALSE );
  965.          IF Kermit_Retry THEN
  966.             Write_Log('   Timed out', FALSE, FALSE )
  967.          ELSE
  968.             Write_Log('   Checksum bad', FALSE, FALSE );
  969.          L := PRED( Kermit_Window_Bottom ) MOD 64;
  970.          REPEAT
  971.             L := SUCC( L ) MOD 64;
  972.             IF Kermit_Queue[L].ACK_Flag THEN
  973.                Write_Log('      Block ' + IToS( L ) + ' ACKED', FALSE, FALSE )
  974.             ELSE
  975.                Write_Log('      Block ' + IToS( L ) + ' NOT ACKED', FALSE, FALSE );
  976.          UNTIL ( L = Kermit_Window_Top );
  977.       END;
  978. }
  979.  
  980. END   (* Send_NAK_For_Most_Desired *);
  981.  
  982. (*----------------------------------------------------------------------*)
  983. (*          OK_Packet_Received --- Handle reception of good packet      *)
  984. (*----------------------------------------------------------------------*)
  985.  
  986. PROCEDURE OK_Packet_Received;
  987.  
  988. BEGIN (* OK_Packet_Received *)
  989.  
  990.    Packet_Num := Rec_Packet_Num;
  991.  
  992.    CASE Kermit_Packet_Type OF
  993.  
  994.       Data_Pack  : Handle_Windowed_Data_Pack;
  995.  
  996.       End_Pack,
  997.       Break_Pack : BEGIN
  998.                                    (* Write any remaining packets to disk *)
  999.  
  1000.                       IF ( NOT Kermit_Abort ) THEN
  1001.                          WHILE ( ( Kermit_Window_Used > 0 ) AND
  1002.                                  ( NOT Kermit_Abort       )     ) DO
  1003.                             BEGIN
  1004.                                Expand_Bottom_Packet;
  1005.                                Update_Kermit_Display;
  1006.                             END;
  1007.  
  1008.                       IF ( Kermit_Packet_Type = Break_Pack ) THEN
  1009.                          Handle_Break_Pack
  1010.                       ELSE
  1011.                          Handle_End_Pack;
  1012.  
  1013.                    END;
  1014.  
  1015.       Attrib_Pack: IF Kermit_Attributes THEN
  1016.                       Handle_Attrib_Pack
  1017.                    ELSE
  1018.                       Send_NAK_For_Most_Desired;
  1019.  
  1020.       Header_Pack: ;
  1021.  
  1022.       ELSE         Send_NAK_For_Most_Desired;
  1023.  
  1024.    END  (* CASE *);
  1025.  
  1026. END   (* OK_Packet_Received *);
  1027.  
  1028. (*----------------------------------------------------------------------*)
  1029. (*          Bad_Packet_Received --- Handle reception of bad packet      *)
  1030. (*----------------------------------------------------------------------*)
  1031.  
  1032. PROCEDURE Bad_Packet_Received;
  1033.  
  1034. BEGIN (* Bad_Packet_Received *)
  1035.  
  1036.    IF ( NOT Kermit_Abort ) THEN
  1037.       BEGIN
  1038.                                    (* Increment tries to get good packet *)
  1039.          Try := SUCC( Try );
  1040.                                    (* Abort transfer if too many *)
  1041.  
  1042.          IF ( Try = Kermit_MaxTry ) THEN
  1043.             BEGIN
  1044.                Kermit_Abort       := TRUE;
  1045.                Kermit_Abort_Level := One_File;
  1046.                Kermit_Construct_Message( 'EToo many retries.' );
  1047.             END
  1048.          ELSE
  1049.             BEGIN
  1050.                                    (* If we're in a retry mode, and an    *)
  1051.                                    (* XOFF was received, the XOFF may be  *)
  1052.                                    (* spurious, so clear it before trying *)
  1053.                                    (* again.  We also need to flush the   *)
  1054.                                    (* comm output buffer at this point    *)
  1055.                                    (* as well.                            *)
  1056.                                    (*                                     *)
  1057.                                    (* If an XOFF wasn't received, perhaps *)
  1058.                                    (* the remote system got a spurious    *)
  1059.                                    (* XOFF, so we send an XON.            *)
  1060.                                    (*                                     *)
  1061.  
  1062.                IF ( Try > 2 ) THEN
  1063.                   IF Async_XOff_Received THEN
  1064.                      BEGIN
  1065.                         Async_Flush_Output_Buffer;
  1066.                         Async_XOff_Received := FALSE;
  1067.                         IF Do_Status_Line THEN
  1068.                            Write_To_Status_Line( '             ', 65 );
  1069.                      END
  1070.                   ELSE
  1071.                      IF Async_Do_XonXoff THEN
  1072.                         IF ( NOT Async_XOFF_Sent ) THEN
  1073.                            Async_Send( CHR( XON ) );
  1074.  
  1075.                                    (* Not too many retries yet --      *)
  1076.                                    (* send NAK for most wanted packet. *)
  1077.  
  1078.                Send_NAK_For_Most_Desired;
  1079.  
  1080.             END;
  1081.  
  1082.       END
  1083.    ELSE
  1084.       BEGIN (* Abort found *)
  1085.  
  1086.          Packet_Num := SUCC( Kermit_Window_Top ) MOD 64;
  1087.  
  1088.          Send_Abort_Packet;
  1089.  
  1090.       END   (* Abort found *);
  1091.  
  1092. END   (* Bad_Packet_Received *);
  1093.  
  1094. (*----------------------------------------------------------------------*)
  1095.  
  1096. BEGIN (* Receive_Windowing *)
  1097.                                    (* Set window size                 *)
  1098.  
  1099.    Window_Size_Used := MAX( His_Kermit_Window_Size , 1 );
  1100.  
  1101.                                    (* Allow more retries when windowing *)
  1102.  
  1103.    Save_Retry       := Kermit_MaxTry;
  1104.    Kermit_MaxTry    := Kermit_MaxTry + Window_Size_Used;
  1105.  
  1106.                                    (* Reset send packet address to free *)
  1107.                                    (* up remainder for packets of table *)
  1108.                                    (* entries.                          *)
  1109.  
  1110.    Send_Packet_Ptr  := ADDR( Sector_Data[100] );
  1111.  
  1112.                                    (* Empty window at this point       *)
  1113.  
  1114.    Kermit_Window_Used   := 0;
  1115.    Kermit_Window_Top    := 0;
  1116.    Kermit_Window_Bottom := 0;
  1117.    Data_Place           := Receive_Offset;
  1118.    Windowing_Started    := FALSE;
  1119. {
  1120.    IF Kermit_Debug THEN
  1121.       BEGIN
  1122.          Write_Log( 'Window_Size   = ' + IToS( Window_Size_Used ) , FALSE, FALSE );
  1123.          Write_Log( 'Window_Used   = ' + IToS( Kermit_Window_Used ) , FALSE, FALSE );
  1124.          Write_Log( 'Window_Top    = ' + IToS( Kermit_Window_Top  ) , FALSE, FALSE );
  1125.          Write_Log( 'Window_Bottom = ' + IToS( Kermit_Window_Bottom ) , FALSE, FALSE );
  1126.          Write_Log( 'Data_Place    = ' + IToS( Data_Place         ) , FALSE, FALSE );
  1127.       END;
  1128. }
  1129.                                    (* Loop over packets in file being *)
  1130.                                    (* received.                       *)
  1131.    REPEAT
  1132.                                    (* Number of tries for a good packet *)
  1133.       Try := 0;
  1134.  
  1135.       REPEAT
  1136.                                    (* Get next packet *)
  1137.          Receive_Packet;
  1138. {
  1139.          IF Kermit_Debug THEN
  1140.             IF Packet_OK THEN
  1141.                Write_Log( 'Receive packet done OK  = ' + IToS( Rec_Packet_Num ),
  1142.                           FALSE, FALSE)
  1143.             ELSE
  1144.                Write_Log( 'Receive packet done BAD = ' + IToS( Rec_Packet_Num ),
  1145.                           FALSE, FALSE);
  1146. }
  1147.                                    (* Handle received packet *)
  1148.  
  1149.          IF Packet_OK THEN
  1150.             OK_Packet_Received
  1151.          ELSE
  1152.             Bad_Packet_Received;
  1153.  
  1154.       UNTIL ( Packet_OK OR Kermit_Abort );
  1155.  
  1156.    UNTIL ( Receive_Done OR Kermit_Abort OR
  1157.            ( Kermit_Packet_Type = Header_Pack ) );
  1158.  
  1159.                                    (* Reset retry counter *)
  1160.    Kermit_MaxTry    := Save_Retry;
  1161.  
  1162.                                    (* Reset send packet pointer address *)
  1163.  
  1164.    Send_Packet_Ptr  := ADDR( Sector_Data[Send_Offset] );
  1165.  
  1166.                                    (* Reset packet number *)
  1167.  
  1168.    Packet_Num       := Rec_Packet_Num;
  1169.  
  1170. END (* Receive_Windowing *);
  1171.  
  1172. (*----------------------------------------------------------------------*)
  1173.  
  1174. BEGIN (* Kermit_Receive_File *)
  1175.                                    (* Assume date/time not received   *)
  1176.    Kermit_Do_File_Date := FALSE;
  1177.    Kermit_Do_File_Time := FALSE;
  1178.                                    (* Remember start time             *)
  1179.  
  1180.    Kermit_Transfer_Start := TimeOfDay;
  1181.  
  1182.                                    (* Perform actual transfer.        *)
  1183.    IF Kermit_Do_Sliding_Win THEN
  1184.       Receive_Windowing
  1185.    ELSE
  1186.       Receive_Normal;
  1187.                                    (* Calculate transfer time *)
  1188.  
  1189.    Kermit_Transfer_End  := TimeOfDay;
  1190.    Total_Time           := Total_Time +
  1191.                            TimeDiff( Kermit_Transfer_Start ,
  1192.                                      Kermit_Transfer_End );
  1193.  
  1194.                                    (* Indicate we're through with transfer *)
  1195.    Kermit_Doing_Transfer := FALSE;
  1196.  
  1197.                                    (* Clear message lines *)
  1198.    IF ( NOT Kermit_Abort ) THEN
  1199.       Kermit_Clear_Message_Lines;
  1200.  
  1201. END    (* Kermit_Receive_File *);
  1202.  
  1203. (*----------------------------------------------------------------------*)
  1204.  
  1205. PROCEDURE Do_Kermit_Receive;
  1206.  
  1207. VAR
  1208.    C_Trans_Rate_E : ShortStr;
  1209.    C_Trans_Rate_A : ShortStr;
  1210.    Rec_Str        : AnyStr;
  1211.    W_Str          : STRING[3];
  1212.    Err            : INTEGER;
  1213.    D_Path         : AnyStr;
  1214.    Save_Close     : BOOLEAN;
  1215.    Get_String     : AnyStr;
  1216.  
  1217. BEGIN  (* Do_Kermit_Receive *)
  1218.                                    (* Hide cursor *)
  1219.    CursorOff;
  1220.                                    (* Save screen *)
  1221.    Save_Screen( Kermit_Local_Save );
  1222.  
  1223.                                    (* Initialize status display information *)
  1224.    Packets_Received   := 0;
  1225.    Packets_Sent       := 0;
  1226.    Packets_Bad        := 0;
  1227.    Buffer_Num         := 0.0;
  1228.    Buffer_Num_Actual  := 0.0;
  1229.    Buffer_Total       := 0.0;
  1230.    Receive_Done       := FALSE;
  1231.    Kermit_MaxTry      := 5;
  1232.    Kermit_Abort       := FALSE;
  1233.    Kermit_Retry       := FALSE;
  1234.    Quoting            := FALSE;
  1235.    Kermit_Abort_Level := No_Abort;
  1236.    Total_Time         := 0.0;
  1237.  
  1238.                                    (* Get title   *)
  1239.    IF FileName <> '' THEN
  1240.       Kermit_Menu_Title := 'Receive file ' + FileName + ' using Kermit'
  1241.    ELSE
  1242.       Kermit_Menu_Title := 'Receive file using Kermit';
  1243.  
  1244.                                    (* Allocate buffer for file data  *)
  1245.  
  1246.    Buffer_Length  := Max_Write_Buffer;
  1247.    Buffer_Size    := Buffer_Length;
  1248.  
  1249.    GetMem( Write_Buffer , Buffer_Length );
  1250.  
  1251.                                    (* Initialize status display              *)
  1252.    Initialize_Display;
  1253.  
  1254.    Write_Log( Kermit_Menu_Title, FALSE, FALSE );
  1255.  
  1256.                                    (* Choose reception method depending upon *)
  1257.                                    (* whether remote system in server mode   *)
  1258.                                    (* or not.                                *)
  1259.  
  1260.    IF Kermit_Remote_Server THEN
  1261.       Kermit_State := Get_File
  1262.    ELSE
  1263.       Kermit_State := Receive_Init;
  1264.  
  1265.                                    (* Transfer not aborted yet               *)
  1266.    Abort_Done := FALSE;
  1267.                                    (* Loop over received packets             *)
  1268.    REPEAT
  1269.                                    (* Take action depending upon current *)
  1270.                                    (* Kermit state.                      *)
  1271.       CASE Kermit_State OF
  1272.  
  1273.          Get_File        : Kermit_Get;
  1274.          Receive_Init    : Kermit_Receive_Init;
  1275.          Receive_Header  : Kermit_Receive_Header;
  1276.          Receive_File    : Kermit_Receive_File;
  1277.  
  1278.       END (* CASE *);
  1279.  
  1280.    UNTIL ( Kermit_Abort OR Receive_Done );
  1281.  
  1282.                                    (* Display transfer rate *)
  1283.  
  1284.    IF ( Receive_Done AND ( NOT Abort_Done ) ) THEN
  1285.       BEGIN
  1286.  
  1287.          Display_Kermit_Message('Receive completed.');
  1288.  
  1289.          IF ( Total_Time = 0.0 ) THEN
  1290.             Total_Time := 1.0;
  1291.  
  1292.          Kermit_Transfer_Rate := Buffer_Total / Total_Time;
  1293.  
  1294.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_E );
  1295.  
  1296.          Display_Kermit_Message_2('Effective transfer rate was ' +
  1297.                                   LTrim( C_Trans_Rate_E ) + ' CPS.');
  1298.  
  1299.          Kermit_Transfer_Rate := Buffer_Num_Actual / Total_Time;
  1300.  
  1301.          STR( Kermit_Transfer_Rate:10:0 , C_Trans_Rate_A );
  1302.  
  1303.          Display_Kermit_Message_3('Actual transfer rate was ' +
  1304.                                   LTrim( C_Trans_Rate_A ) + ' CPS.');
  1305.  
  1306.       END;
  1307.  
  1308.    IF Abort_Done THEN
  1309.       Write_Log('Receive cancelled.' , TRUE , FALSE );
  1310.  
  1311.                                    (* Ensure entire protocol aborted   *)
  1312.                                    (* if requested.                    *)
  1313.    Kermit_Done := Abort_Done;
  1314.  
  1315.    DELAY( Two_Second_Delay );
  1316.                                    (* Remove download buffer           *)
  1317.    FREEMEM( Write_Buffer , Buffer_Length );
  1318.  
  1319.                                    (* Remove Kermit window             *)
  1320.  
  1321.    IF ( Kermit_Local_Save <> NIL ) THEN
  1322.       BEGIN
  1323.          Restore_Screen( Kermit_Local_Save );
  1324.          Reset_Global_Colors;
  1325.       END;
  1326.                                    (* Display cursor again *)
  1327.    CursorOn;
  1328.                                    (* Signal transfer done *)
  1329.    IF ( NOT Silent_Mode ) THEN
  1330.       FOR I := 1 TO Transfer_Bells DO
  1331.          Menu_Beep;
  1332.  
  1333. END    (* Do_Kermit_Receive *);
  1334.  
  1335. (*----------------------------------------------------------------------*)
  1336.  
  1337. PROCEDURE Get_File_Pattern;
  1338.  
  1339. BEGIN (* Get_File_Pattern *)
  1340.  
  1341.    Save_Partial_Screen( Local_Save, 10, 5, 78, 8 );
  1342.  
  1343.    Draw_Menu_Frame( 10, 5, 78, 8, Menu_Frame_Color, Menu_Title_Color,
  1344.                     Menu_Text_Color, '' );
  1345.  
  1346.    Window( 11, 6, 77, 7 );
  1347.  
  1348.    GoToXY( 2 , 1 );
  1349.  
  1350.    WRITE('File to receive: ');
  1351.                                    (* See if keyed in before *)
  1352.  
  1353.    IF ( LENGTH( FileName ) = 0 ) THEN
  1354.       IF Auto_Find_FileNames THEN
  1355.          Get_Auto_File_Name( Saved_Kbd_File_Name , FileName );
  1356.  
  1357.    IF ( ( NOT ( Host_Mode OR Script_Transfer ) ) OR ( LENGTH( FileName ) = 0 ) ) THEN
  1358.       BEGIN
  1359.          FileName := FileName;
  1360.          Read_Edited_String( FileName );
  1361.          IF ( FileName = CHR( ESC ) ) THEN
  1362.             FileName := '';
  1363.          WRITELN;
  1364.       END
  1365.    ELSE
  1366.       WRITELN( FileName );
  1367.  
  1368.    Restore_Screen( Local_Save );
  1369.    Reset_Global_Colors;
  1370.  
  1371. END   (* Get_File_Pattern *);
  1372.  
  1373. (*----------------------------------------------------------------------*)
  1374.  
  1375. BEGIN (* Receive_Kermit_File *)
  1376.                                    (* Get Kermit menu *)
  1377.  
  1378.    Make_A_Menu( Kermit_Menu, Receive_Quit_Item, 6, 20, 40, 9, Receive_Quit_Item,
  1379.                 'Choose Kermit function: ',
  1380.                 'a) GET Text File;b) GET Binary file;c) RECEIVE Text File;' +
  1381.                 'd) RECEIVE Binary File;' +
  1382.                 'f) Finish Remote Server;l) Logout Remote Server;' +
  1383.                 'r) Remote Server Commands;t) Transfer to Send File Menu;' +
  1384.                 'q) Quit Kermit',
  1385.                 FALSE );
  1386.  
  1387.    Kermit_Done            := FALSE;
  1388.    Sending_File           := FALSE;
  1389.    Host_Count             := 0;
  1390.    Send_Packet_Ptr        := ADDR( Sector_Data[Send_Offset] );
  1391.    Send_Packet_Ptr^[2]    := CHR( 0 );
  1392.    Send_Packet_Ptr^[3]    := CHR( 0 );
  1393.    Send_Packet_Ptr^[4]    := CHR( 0 );
  1394.  
  1395.    REPEAT
  1396.                                    (* Reinitialize Kermit variables *)
  1397.       Kermit_Init;
  1398.  
  1399.       Remote_Comm := '';
  1400.                                    (* Display Kermit receive menu  *)
  1401.  
  1402.       IF ( NOT ( Host_Mode OR Script_Transfer ) ) THEN
  1403.          BEGIN
  1404.             Menu_Display_Choices( Kermit_Menu );
  1405.             Menu_Choice := Menu_Get_Choice( Kermit_Menu , Erase_Menu );
  1406.          END
  1407.       ELSE
  1408.          BEGIN
  1409.  
  1410.             Host_Count := SUCC( Host_Count );
  1411.  
  1412.             IF ( Host_Count = 1 ) THEN
  1413.                BEGIN
  1414.  
  1415.                   IF Kermit_File_Type_Var <> Kermit_Binary THEN
  1416.                      IF ( LENGTH( FileName ) > 0 ) THEN
  1417.                         Menu_Choice := 1
  1418.                      ELSE
  1419.                         Menu_Choice := 3
  1420.                   ELSE
  1421.                      IF ( LENGTH( FileName ) > 0 ) THEN
  1422.                         Menu_Choice := 2
  1423.                      ELSE
  1424.                         Menu_Choice := 4;
  1425.  
  1426.                   IF ( LENGTH( FileName ) > 0 ) THEN
  1427.                      IF ( FileName[1] = '/' ) THEN
  1428.                         BEGIN
  1429.                            Menu_Choice := 7;
  1430.                            Remote_Comm := FileName;
  1431.                         END;
  1432.  
  1433.                END
  1434.             ELSE
  1435.                Menu_Choice := Receive_Quit_Item;
  1436.  
  1437.          END;
  1438.                                    (* Perform desired Kermit function *)
  1439.       CASE Menu_Choice OF
  1440.  
  1441.          1: BEGIN
  1442.                Kermit_File_Type_Var := Kermit_Ascii;
  1443.                Get_File_Pattern;
  1444.                Kermit_Remote_Server := TRUE;
  1445.                IF ( LENGTH( FileName ) > 0 ) THEN
  1446.                   Do_Kermit_Receive;
  1447.             END;
  1448.  
  1449.          2: BEGIN
  1450.                Kermit_File_Type_Var := Kermit_Binary;
  1451.                Get_File_Pattern;
  1452.                Kermit_Remote_Server := TRUE;
  1453.                IF ( LENGTH( FileName ) > 0 ) THEN
  1454.                   Do_Kermit_Receive;
  1455.             END;
  1456.  
  1457.          3: BEGIN
  1458.                Kermit_File_Type_Var := Kermit_Ascii;
  1459.                FileName := '';
  1460.                Kermit_Remote_Server := FALSE;
  1461.                Do_Kermit_Receive;
  1462.             END;
  1463.  
  1464.          4: BEGIN
  1465.                Kermit_File_Type_Var := Kermit_Binary;
  1466.                FileName := '';
  1467.                Kermit_Remote_Server := FALSE;
  1468.                Do_Kermit_Receive;
  1469.             END;
  1470.  
  1471.          5: BEGIN
  1472.                Kermit_Finish_Server( 'F' );
  1473.             END;
  1474.  
  1475.          6: BEGIN
  1476.                Kermit_Finish_Server( 'L' );
  1477.             END;
  1478.  
  1479.          7: BEGIN
  1480.                Kermit_Remote_Commands( Remote_Comm , Do_A_Receive );
  1481.                FileName := '';
  1482.                Kermit_Remote_Server := FALSE;
  1483.                IF Do_A_Receive THEN
  1484.                   Do_Kermit_Receive;
  1485.             END;
  1486.  
  1487.          8: BEGIN
  1488.                Kermit_Done  := TRUE;
  1489.                Sending_File := TRUE;
  1490.             END;
  1491.  
  1492.          ELSE
  1493.             BEGIN
  1494.                Kermit_Done := TRUE;
  1495.             END;
  1496.  
  1497.       END (* CASE *);
  1498.  
  1499.    UNTIL Kermit_Done;
  1500.                                    (* Ensure status window restored        *)
  1501.    IF Do_Status_Line THEN
  1502.       Window( 1, 1, Max_Screen_Col, Max_Screen_Line - 1 );
  1503.  
  1504.                                    (* Ensure switch to send code if needed *)
  1505.  
  1506.    Kermit_Really_Done := ( NOT Sending_File );
  1507.    FileName           := '';
  1508.  
  1509. END   (* Receive_Kermit_File *);
  1510.